/*********************************************************
/* kernel.c						 *
/* Kernel - main					 *
/*********************************************************/

#include <mem.h>
#include <multiboot.h>
#include <kernel.h>
#include <common.h>
#include <mm.h>

extern int __end;
extern int __start;

const Bool VERBOSE = FALSE;

void kmain(unsigned long addr, unsigned long magic);

/*Main method*/
void kmain(unsigned long addr, unsigned long magic) {

	__asm__("cli");
	int_init();
	/*__asm__("sti");*/

	multiboot_info_t *mbi;

	k_initvideo();		/* Initialize the video device */

	if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
    	{
      		printf ("Invalid magic number: 0x%x\n", (unsigned) magic);
      		return;
    	}
	
	/* Set MBI to the address of the Multiboot information structure. */
  	mbi = (multiboot_info_t *) addr;

	k_clear_screen();	/* Clear all contents of the screen */
	
	/* Print out welcome message */
	k_print_welcomemsg(1,0);

	if (CHECK_FLAG (mbi->flags, 0)) {
		k_printmemmap((unsigned) mbi->mem_lower,(unsigned) mbi->mem_upper,1,2);
	} else {
		printf("Error: Memory map is invalid.  Consider alternate methods of probing memory.\n\n");	
	}
	
	unsigned char * usableMem;
	
	/* Are mmap_* valid?*/
  	if (CHECK_FLAG (mbi->flags, 6))
    	{
      		memory_map_t *m = ((memory_map_t *)mbi->mmap_addr);
      		int length = (int)mbi->mmap_length;
      		while (length > 0) {
			if (m->type==1) {
				if (VERBOSE == TRUE) {
					printf("Usable RAM: Base Address: 0x%x * 4.0GB + 0x%x,\n     Length: 0x%x * 4.0GB + 0x%x bytes.\n", m->base_addr_high, m->base_addr_low, m->length_high, m->length_low);
				}
				usableMem = m->length_low;
				usableMem++;
			} else {
				if (VERBOSE == TRUE) {
					printf("Reserved RAM: Base Address: 0x%x * 4.0GB + 0x%x,\n     Length: 0x%x * 4.0GB + 0x%x bytes.\n", m->base_addr_high, m->base_addr_low, m->length_high, m->length_low);
				}
			}
			length -= (m->size + sizeof(m->size));
			m = (memory_map_t *) (((unsigned) m) + m->size + sizeof(m->size));
      		}
    	} else {
		printf("Error: mmap invalid!\n");
	}

	char* endOfKernel = &__end;
	char* startOfKernel = &__start;
	char* sizeOfKernel = endOfKernel - startOfKernel;

	if (VERBOSE == TRUE) {
		printf("Kernel location and size:\n");
		printf("Kernel starts at: %d bytes.  addr: 0x%x\n", startOfKernel, startOfKernel); 
		printf("Kernel ends at: %d bytes.  addr: 0x%x\n", endOfKernel, endOfKernel); 
		printf("Kernel size: %d bytes.  addr: 0x%x\n\n", sizeOfKernel, sizeOfKernel);
	}

	/* Remember:  Usable memory starts after the kernel end address (i.e. endOfKernel).*/

	printf("Performing additional setup (Interrupt Tables, GDT, etc.)\n");

	/* Write code for any setup needed */
	printf("Initializing subsystems (Memory manager, filesystem, etc.)\n");

	mm_init(endOfKernel+1, usableMem);	/* Initialize the first fit memory manager.
						   Do not call malloc() or free() before
						   mm_init has been called */

	printf("Loading drivers ...\n");
	
	/* Write code to load drivers that might be required */

	printf("Starting console ...\n\n");
	

	/* Write code to present a console input to use */


        for (;;)
		__asm__("hlt");
}

